<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <h2>一、DOM</h2>
  <div>文档对象模型 (DOM) 是 HTML 和 XML 文档的编程接口.</div>
  <h2>二、操作</h2>
  <div>下面就来分析DOM常见的操作，主要分为：</div>
  <ul>
    <li>创建节点</li>
    <li>查询节点</li>
    <li>更新节点</li>
    <li>添加节点</li>
    <li>删除节点</li>
  </ul>
  <div>每个DOM元素还有parentNode、childNodes、firstChild、lastChild、nextSibling、previousSibling属性。</div>
  <br>
  <div id="p"></div>
  <br>
  <div id="p-id"></div>
  <br>
  <!-- HTML结构 -->
  <p id="js"></p>
  <div id="list">
      <p id="java">Java</p>
      <p id="python">Python</p>
      <p id="scheme">Scheme</p>
  </div>
  <div id="id">id</div>
  <div id="to-be-removed">to-be-removed</div>
  <script>
    // 创建节点
    // createElement 创建新元素
    const divEl = document.createElement("div");
    console.log(divEl,'创建div节点');
    // createTextNode 创建一个文本节点
    const textEl = document.createTextNode("content",'文本节点');

    // createDocumentFragment 创建一个文档碎片 主要是用来存储临时节点
    // 当请求把一个DocumentFragment 节点插入文档树时，插入的不是 DocumentFragment自身，而是它的所有子孙节点
    const fragment = document.createDocumentFragment();
    console.log(fragment,'文档碎片');

    // createAttribute 创建属性节点，可以是自定义属性
    const dataAttribute = document.createAttribute('custom');
    console.log(dataAttribute,'属性节点');


    // 获取节点
    // querySelector 传入任何有效的css 选择器，即可选中单个 DOM元素（首个）：
    document.querySelector('.element')
    document.querySelector('#element')
    document.querySelector('div')
    document.querySelector('[name="username"]')
    document.querySelector('div + p > span')
    //如果页面上没有指定的元素时，返回 null
    console.log(document.querySelector('div + p > span'),'查询不到节点的输出');
    
    
    // querySelectorAll 返回一个与之相匹配的Element节点列表
    const notLive = document.querySelectorAll("p");
    // 没有相匹配的，则返回一个空节点列表
    console.log(notLive);
    // document.getElementById('id属性值');返回拥有指定id的对象的引用
    // document.getElementsByClassName('class属性值');返回拥有指定class的对象集合
    // document.getElementsByTagName('标签名');返回拥有指定标签名的对象集合
    // document.getElementsByName('name属性值'); 返回拥有指定名称的对象结合
    // document/element.querySelector('CSS选择器');  仅返回第一个匹配的元素
    // document/element.querySelectorAll('CSS选择器');   返回所有匹配的元素
    // document.documentElement;  获取页面中的HTML标签
    // console.log(document.documentElement);
    // document.body; 获取页面中的BODY标签
    // console.log(document.body,'document.body');
    // document.all[''];  获取页面中的所有元素节点的对象集合型
    // console.log(document.all['']);
    // 除此之外，每个DOM元素还有parentNode、childNodes、firstChild、lastChild、nextSibling、previousSibling属性。
    console.log(document.body.childNodes);


    // 更新节点
    // innerHTML 不但可以修改一个DOM节点的文本内容，还可以直接通过HTML片段修改DOM节点内部的子树
    // 获取<p id="p">...</p>
    var p = document.getElementById('p');
    // 设置文本为abc:
    p.innerHTML = 'ABC'; // <p id="p">ABC</p>
    // 设置HTML:
    // p.innerHTML = 'ABC <span style="color:red">RED</span> XYZ';
    // <p>...</p>的内部结构已修改

    // innerText、textContent 自动对字符串进行HTML编码，保证无法设置任何HTML标签,两者的区别在于读取属性时，innerText不返回隐藏元素的文本，而textContent返回所有文本

    // style DOM节点的style属性对应所有的CSS，可以直接获取或设置。遇到-需要转化为驼峰命名
    // 获取<p id="p-id">...</p>
    // const p = document.getElementById('p-id');
    // 设置CSS:
    p.style.color = '#ff0000';
    p.style.fontSize = '20px'; // 驼峰命名
    p.style.paddingTop = '2em';



    // 添加节点
    // innerHTML 如果这个DOM节点是空的，例如，<div></div>，那么，直接使用innerHTML = '<span>child</span>'就可以修改DOM节点的内容，相当于添加了新的DOM节点,如果这个DOM节点不是空的，那就不能这么做，因为innerHTML会直接替换掉原来的所有子节点
    const js = document.getElementById('js')
    js.innerHTML = "JavaScript"

    // appendChild 把一个子节点添加到父节点的最后一个子节点
    const list = document.getElementById('list');
    list.appendChild(js);
    // 上述代码中，我们是获取DOM元素后再进行添加操作，这个js节点是已经存在当前文档树中，因此这个节点首先会从原先的位置删除，再插入到新的位置,如果动态添加新的节点，则先创建一个新的节点，然后插入到指定的位置
    // const list = document.getElementById('list'),
    const haskell = document.createElement('p');
    haskell.id = 'haskell';
    haskell.innerText = 'Haskell';
    list.appendChild(haskell);

    
    // insertBefore 把子节点插入到指定的位置 子节点会插入到referenceElement之前
    // parentElement.insertBefore(newElement, referenceElement)


    // setAttribute
    // 在指定元素中添加一个属性节点，如果元素中已有该属性改变属性值
    const divElP = document.getElementById('id')
    divElP.setAttribute('class', 'white');//第一个参数属性名，第二个参数属性值。

    
    // 删除节点
    // 删除一个节点，首先要获得该节点本身以及它的父节点，然后，调用父节点的removeChild把自己删掉
    // 删除后的节点虽然不在文档树中了，但其实它还在内存中，可以随时再次被添加到别的位置
    // 拿到待删除节点:
    const self = document.getElementById('to-be-removed');
    // 拿到父节点:
    const parent = self.parentElement;
    // 删除:
    const removed = parent.removeChild(self);
    removed === self; // true
  </script>
</body>
</html>